package com.chenqi.tool.view

import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.View
import android.widget.LinearLayout
import com.chenqi.tool.R
import kotlin.math.max

/**
 * 作者: CQ
 * 日期: 2021-07-14
 * 说明: 自动换行的LinearLayout
 */
class LinearLayoutAuto @JvmOverloads constructor(
    context : Context,
    attrs : AttributeSet? = null,
    defStyleAttr : Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
    private var childHorizontalSpacing = 0 // 横向间距
    private var childVerticalSpacing = 0 // 纵向间距
    private var alignment = 0 // 对齐方式
    private val listPointText = mutableListOf<PointText>()
    private val mapMaxWidth = mutableMapOf<Int, Int>() // 每行最大宽度[行，宽度]

    init {
        val typedArray = context.obtainStyledAttributes(attrs, R.styleable.LinearLayoutAuto)
        childHorizontalSpacing = typedArray.getDimension(R.styleable.LinearLayoutAuto_childHorizontalSpacing, 0f).toInt()
        childVerticalSpacing = typedArray.getDimension(R.styleable.LinearLayoutAuto_childVerticalSpacing, 0f).toInt()
        alignment = typedArray.getInt(R.styleable.LinearLayoutAuto_alignment, 0)
    }

    override fun onMeasure(widthMeasureSpec : Int, heightMeasureSpec : Int) {
        if (childCount == 0) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec)
            return
        }

        val width = MeasureSpec.getSize(widthMeasureSpec)
        var height = MeasureSpec.getSize(heightMeasureSpec)
        val heightMode = MeasureSpec.getMode(heightMeasureSpec)

        //如果有子view，行数肯定至少1行
        var lineCount = 1
        var childLeft : Int
        var childTop : Int
        var childRight : Int
        var childBottom : Int
        listPointText.clear()
        var maxHeightItem = 0
        //此布局高度一般是wrap_content,所以需要对AT_MOST模式做处理
        if (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED) {
            var childrenTotalWidth = 0 //子View的宽度之和
            var childView : View?
            //循环子View，分别测量子View的宽高
            for (i in 0 until childCount) {
                childView = getChildAt(i)
                if (childView.visibility != View.GONE) {
                    measureChild(childView, widthMeasureSpec, heightMeasureSpec) //测量子View
                    var childWidth = childView.measuredWidth + childHorizontalSpacing
                    if (childWidth > width) {
                        return
                    }
                    childrenTotalWidth += childWidth //把子View的宽度和margin属性做加和
                    // 相加的子view宽度之和大于布局的宽度
                    if (childrenTotalWidth > width) {
                        //行数加1
                        lineCount++
                        //把子view的总宽度置为当前子view的宽度，以便后续的子view宽度的继续加和操作
                        childrenTotalWidth = childWidth //把子View的宽度和margin属性做加和
                    }
                    if (childrenTotalWidth == childWidth) {
                        childWidth += childHorizontalSpacing
                        childrenTotalWidth += childHorizontalSpacing
                    }
                    mapMaxWidth[lineCount] = childrenTotalWidth
                    val childHeight = if (lineCount == 1) {
                        childView.measuredHeight + childVerticalSpacing * 2
                    } else {
                        childView.measuredHeight + childVerticalSpacing
                    }
                    childLeft = childrenTotalWidth - childView.measuredWidth - childHorizontalSpacing
                    childRight = childLeft + childView.measuredWidth
                    childTop = childHeight * (lineCount - 1) + childVerticalSpacing
                    childBottom = childTop + childView.measuredHeight
                    listPointText.add(PointText(i, lineCount, childLeft, childTop, childRight, childBottom))
                    maxHeightItem = max(maxHeightItem, childView.measuredHeight)
                }
            }
            //循环结束，即可得到lineCount的值
            //注意这里设置的所有的子View的topMargin和bottomMargin分别一样。
            //由于子View的高度一致，所以取第一个子View的高度和其上下margin属性，乘以行数，即可得到layout在AT_MOST模式下总高度
            height = (maxHeightItem + childVerticalSpacing) * lineCount + childVerticalSpacing
        }
        setMeasuredDimension(width, height)
        Log.e("测量", "width = $width, height = $height")
    }

    @SuppressLint("DrawAllocation")
    override fun onLayout(changed : Boolean, l : Int, t : Int, r : Int, b : Int) {
        if (childCount == 0) {
            return
        }
        var deviationH = 0 // 横向偏移量（对齐使用）
        //子view的总宽度，用来做折行判断，并计算出所有位于每一行行首的子View的索引
        listPointText.forEach {
            if (alignment == 1) {
                deviationH = width - mapMaxWidth[it.line]!!
            }
            getChildAt(it.i).layout(it.left + deviationH, it.top, it.right + deviationH, it.bottom)
            Log.e("text ${it.i}", "line = ${it.line}, left = ${it.left}, top = ${it.top}, right = ${it.right}, bottom = ${it.bottom}")
        }
    }

    /**
     * i 位置
     * line  第几行
     * left 左侧
     * top 上侧
     * right 右侧
     * bottom 地测
     */
    data class PointText(var i : Int, var line : Int, var left : Int, var top : Int, var right : Int, var bottom : Int)
}